<script>
import { createPopper } from '@popperjs/core';
import { GlDropdown, GlIcon, GlButton } from '@gitlab/ui';
import HelpPopover from '~/vue_shared/components/help_popover.vue';
import { VULNERABILITY_STATE_OBJECTS, DISMISSAL_REASONS } from '../constants';

export default {
  states: Object.values(VULNERABILITY_STATE_OBJECTS),
  DISMISSAL_REASONS,
  components: { GlDropdown, GlIcon, GlButton, HelpPopover },
  inject: ['dismissalDescriptions'],
  props: {
    initialState: { type: String, required: true },
    initialDismissalReason: { type: String, required: false, default: null },
    disabled: { type: Boolean, required: false, default: false },
  },

  data() {
    return {
      selectedState: VULNERABILITY_STATE_OBJECTS[this.initialState],
      selectedDismissalReason: this.initialDismissalReason,
      showDismissalDropdown: false,
    };
  },

  computed: {
    initialStateItem() {
      return VULNERABILITY_STATE_OBJECTS[this.initialState];
    },
    buttonText() {
      return this.initialStateItem?.buttonText;
    },
    isSaveDisabled() {
      return (
        this.selectedState === this.initialStateItem &&
        this.selectedDismissalReason === this.initialDismissalReason
      );
    },
  },

  watch: {
    initialStateItem(newItem) {
      this.selectedState = newItem;
    },
    initialDismissalReason(newItem) {
      this.selectedDismissalReason = newItem;
    },
  },

  beforeDestroy() {
    this.destroyPopper();
  },

  methods: {
    changeSelectedState(newState) {
      if (newState.action === 'dismiss') {
        return;
      }
      this.selectedState = newState;
      this.selectedDismissalReason = null;
    },
    changeSelectedStateAndDismissalReason(newState, dismissalReason) {
      this.selectedState = newState;
      this.selectedDismissalReason = dismissalReason;
    },
    closeDropdown() {
      this.$refs.dropdown.hide();
    },
    resetDropdown() {
      this.selectedState = this.initialStateItem;
      this.selectedDismissalReason = this.initialDismissalReason;
    },
    save(selectedState, selectedDismissalReason) {
      let state = selectedState;

      if (selectedDismissalReason) {
        state = { ...selectedState };
        // dismissalReason needs to be passed in uppercase to vulnerability_dismiss mutation
        state.payload.dismissalReason = selectedDismissalReason.toUpperCase();
        // when a reason is provided, we delete the fixOrFalsePositive default comment
        delete state.payload.comment;
      }

      this.$emit('change', state);

      this.closeDropdown();
    },
    handleMouseover(event, action) {
      if (action !== 'dismiss') {
        return;
      }

      this.createDismissalDropdown(event.currentTarget);
    },
    handleMouseleave() {
      this.destroyPopper();
      this.showDismissalDropdown = false;
    },
    destroyPopper() {
      if (this.popper) {
        this.popper.destroy();
        this.popper = null;
      }
    },
    async createDismissalDropdown(ref) {
      if (this.popper) {
        return;
      }
      this.showDismissalDropdown = true;
      // await nextTick here such that dropdown element is mounted
      await this.$nextTick();
      const [dropdown] = this.$refs.dismissalReasonDropdown;
      this.popper = createPopper(ref, dropdown, this.$options.defaultPopperOptions);
    },
    getPopoverOptions(title, reason) {
      return {
        ...this.$options.defaultPopoverOptions,
        title,
        content: this.dismissalDescriptions[reason],
      };
    },
  },
  defaultPopperOptions: {
    placement: 'right-start',
    modifiers: [
      {
        name: 'flip',
        options: {
          fallbackPlacements: ['left-start', 'bottom'],
        },
      },
    ],
  },
  defaultPopoverOptions: {
    boundary: 'viewport',
    cssClasses: ['gl-pointer-events-none'],
  },
};
</script>

<template>
  <gl-dropdown
    ref="dropdown"
    data-testid="vulnerability-status-dropdown"
    menu-class="vulnerability-state-dropdown dropdown-extended-height gl-p-0 gl-overflow-visible!"
    :text="buttonText"
    :right="true"
    :disabled="disabled"
    @hide="resetDropdown"
  >
    <li
      v-for="stateItem in $options.states"
      :key="stateItem.action"
      :data-testid="stateItem.state"
      class="dropdown-item gl-display-flex! gl-align-items-center gl-py-5! gl-px-3! gl-overflow-visible! gl-cursor-pointer border-bottom"
      :class="{
        selected: selectedState === stateItem,
        'gl-cursor-default!': stateItem.action === 'dismiss',
      }"
      @click="changeSelectedState(stateItem)"
      @mouseover="handleMouseover($event, stateItem.action)"
      @mouseleave="handleMouseleave()"
    >
      <div class="gl-flex-direction-column gl-flex-grow-1">
        <div class="gl-display-flex gl-align-items-center">
          <gl-icon
            v-if="selectedState === stateItem"
            class="selected-icon gl-absolute"
            name="status_success_borderless"
            :size="24"
          />
          <div class="gl-pl-6 gl-font-weight-bold">{{ stateItem.dropdownText }}</div>
        </div>
        <div class="gl-pl-6">
          <template v-if="stateItem.action === 'dismiss'">
            <template v-if="selectedDismissalReason">
              {{ $options.DISMISSAL_REASONS[selectedDismissalReason] }}
            </template>
            <template v-else>
              {{ __('Select a reason') }}
            </template>
          </template>
          <template v-else>
            {{ stateItem.dropdownDescription }}
          </template>
        </div>
      </div>
      <template v-if="stateItem.action === 'dismiss'">
        <gl-icon name="chevron-right" :size="16" />

        <ul
          v-if="showDismissalDropdown"
          ref="dismissalReasonDropdown"
          data-testid="dismissal-reason-dropdown"
          role="menu"
          class="dropdown-menu gl-px-0 gl-py-3!"
        >
          <li
            v-for="(text, reason) in $options.DISMISSAL_REASONS"
            :key="reason"
            :data-testid="reason"
            role="menuitem"
            class="dropdown-item dismissal-reason gl-px-3! gl-cursor-pointer"
            :class="{
              selected: selectedDismissalReason === reason,
            }"
            @click="changeSelectedStateAndDismissalReason(stateItem, reason)"
          >
            <div class="gl-display-flex gl-flex-direction-row gl-align-items-center">
              <gl-icon
                v-if="selectedDismissalReason === reason"
                class="selected-icon gl-absolute"
                name="status_success_borderless"
                :size="24"
              />
              <div class="gl-pl-6">{{ text }}</div>
              <help-popover
                :options="getPopoverOptions(text, reason)"
                class="dismissal-reason-popover gl-display-inline-flex gl-visibility-hidden"
              />
            </div>
          </li>
        </ul>
      </template>
    </li>

    <template #footer>
      <div class="gl-text-right gl-px-3">
        <gl-button ref="cancel-button" class="gl-mr-3" @click="closeDropdown">
          {{ __('Cancel') }}
        </gl-button>
        <gl-button
          ref="save-button"
          data-testid="vulnerability-save-status-button"
          variant="confirm"
          :disabled="isSaveDisabled"
          @click="save(selectedState, selectedDismissalReason)"
        >
          {{ s__('VulnerabilityManagement|Change status') }}
        </gl-button>
      </div>
    </template>
  </gl-dropdown>
</template>
